﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.ServiceModel.DomainServices.Client;
using AbstraX.TypeMappings;
using System.Collections;
using System.IO;
using MvvmTreeView;
using AbstraX;

namespace AbstraX.ClientInterfaces
{
    public delegate void ChildrenLoadedHandler(IBase parent);

    public enum ProviderType : int
    {
        BusinessModel,
        ViewModel,
        EntityMap,
        AssemblyMap,
        ParsedCode,
        ResourceMap,
        WebService,
        CodeModel,
        ServerModel,
        ODATA,
        JSON,
        ASPX,
        XAML,
        URLDocument,
        HTML,
        XML,
        SQL,
        Custom
    }

    public enum DefinitionKind
    {
        Unknown = 0,
        Class = 1,
        Delegate = 2,
        Enumeration = 3,
        Interface = 4,
        Structure = 5,
        Constructor = -1,
        Event = -2,
        Field = -3,
        Method = -4,
        Operator = -5,
        Property = -6,
        NotApplicable = 100
    }

    [Flags]
    public enum Modifiers : int
    {
        Unknown = 0,
        CanRead = 1,
        CanWrite = 2,
        IsLocal = 4,
        NotNavigable = 8,
        NotApplicable = 4096
    }

    public enum EntityType : int
    {
        Root,
        Element
    }

    public enum OperationDirection : int
    {
        Incoming,
        Outgoing
    }

    public interface IRoot : IBase
    {
        string ParentFieldName { get; }
        string URL { get; }
        ProviderType ProviderType { get; }
        IType DataType { get; }
        IEnumerable<IElement> RootElements { get; }
        void LoadChildren();
        event ChildrenLoadedHandler ChildrenLoaded;
        ItemGenerationOperation<T> GenerateItemFromID<T>(string id) where T : IBase;
    }

    public interface IType
    {
        string Name { get; }
        string FullyQualifiedName { get; }
        bool IsCollectionType { get; set; }
        BaseType CollectionType { get; set; }
        bool IsImageType { get; set; }
        string SuggestedNamespace { get; set; }
    }

    public interface IScalarType : IType
    {
        XmlTypeCode TypeCode { get; }
        bool Supports(Type dotNetType);
    }

    public interface IParentBase : IBase
    {
        event ChildrenLoadedHandler ChildrenLoaded;
        void LoadChildren();
        IEnumerable<IElement> ChildElements { get; }
        IRoot Root { get; }
    }

    public class ItemGeneratedEventArgs<T> : EventArgs where T : IBase
    {
        public T Item { get; set; }

        public ItemGeneratedEventArgs()
        {
        }

        public ItemGeneratedEventArgs(T item)
        {
            this.Item = item;
        }
    }

    public class ProgressEventArgs : EventArgs
    {
        public float PercentComplete { get; private set; }

        public ProgressEventArgs(float percentComplete)
        {
            this.PercentComplete = percentComplete;
        }
    }

    public class ExceptionEventArgs : EventArgs
    {
        public Exception Exception { get; set; }

        public ExceptionEventArgs()
        {
        }

        public ExceptionEventArgs(Exception ex)
        {
            this.Exception = ex;
        }
    }

    public delegate void ItemGeneratedHandler<T>(object sender, ItemGeneratedEventArgs<T> e) where T : IBase;
    public delegate void ExceptionHandler(object sender, ExceptionEventArgs e);

    public class ItemGenerationOperation<T> where T : IBase
    {
        public event ItemGeneratedHandler<T> Generated;
        public event ExceptionHandler ExceptionOccured;
        public event EventHandler<ProgressEventArgs> OnProgress;
        public Exception Exception { get; set; }

        public ItemGenerationOperation()
        {
        }

        public ItemGenerationOperation(Exception ex)
        {
            this.Exception = ex;
        }

        public bool HasException
        {
            get
            {
                return this.Exception != null;
            }
        }

        public void SetProgress(float percentComplete)
        {
            if (OnProgress != null)
            {
                OnProgress(this, new ProgressEventArgs(percentComplete));
            }
        }

        public void SetGenerated(object sender, T item)
        {
            Generated(sender, new ItemGeneratedEventArgs<T>(item));
        }

        public void SetException(object sender, Exception ex)
        {
            this.Exception = ex;
            ExceptionOccured(sender, new ExceptionEventArgs(ex));
        }
    }

    public class BaseType : IType
    {
        public string Name { get; set;  }
        public string FullyQualifiedName { get; set; }
        public string AssemblyQualifiedName { get; set; }
        public string Namespace { get; set; }
        public bool IsCollectionType { get; set; }
        public BaseType CollectionType { get; set; }
        public bool IsImageType { get; set; }
        public string SuggestedNamespace { get; set; }

        public BaseType()
        {
        }

        public BaseType(Type type)
        {
            this.Name = type.Name;
            this.FullyQualifiedName = type.FullName;

            if (type.IsDictionaryGeneric())
            {
                IsCollectionType = true;
                CollectionType = new BaseType(type.GetDictionaryGenericType());
            }
            else if (type.IsEnumerableGeneric())
            {
                IsCollectionType = true;
                CollectionType = new BaseType(type.GetEnumerableGenericType());
            }
        }
    }

    public class Argument
    {
        public string Parameter { get; set; }
        public string Value { get; set; }
    }

    public class Facet
    {
        public BaseType FacetType;
        public List<Argument> Arguments;
    }

    public class ScalarType : BaseType, IScalarType
    {
        public XmlTypeCode TypeCode { get; set;  }

        public ScalarType()
        {
        }

        public ScalarType(Type type) : base(type)
        {
            this.TypeCode = type.GetXMLType();
        }

        public bool Supports(Type dotNetType)
        {
            return dotNetType.MapsTo(this.TypeCode);
        }
    }

    public interface IBase : IAbstraXDocument
    {
        string ID { get; }
        string ParentID { get; }
        string Name { get; }
        string DesignComments { get; }
        string Documentation { get; }
        string DocumentationSummary { get; }
        bool HasDocumentation { get; }
        string ImageURL { get; }
        float ChildOrdinal { get; }
        string DebugInfo { get; }
        IBase Parent { get; }
        string FolderKeyPair { get; }
        DomainContext Context { get; set; }
        DefinitionKind Kind { get; }
        Modifiers Modifiers { get; }
        bool HasChildren { get; }
        bool IsChildrenLoaded { get; }
#if SILVERLIGHT
        IAbstraXExtension LoadExtension(IBase baseObject, ITreeNode treeNode);
        IAbstraXExtension LoadExtension(IBase baseObject);
#endif
    }

    public interface IAttribute : IParentBase
    {
        IScalarType DataType { get; }
    }

    public interface IOperation : IParentBase
    {
        OperationDirection Direction { get; }
    }

    public interface IElement : IParentBase
    {
        bool IsContainer { get; }
        IType DataType { get; }
        IEnumerable<IAttribute> Attributes { get; }
        IEnumerable<IOperation> Operations { get; }
    }
}
